/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 dump_entire_map_image.cpp

	$Header: /heroes4/dump_entire_map_image.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#include "dump_entire_map_image.h"

#include <fstream>
#include <memory>
#include <string.h>

#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "convert_16_bit.h"
#include "memory_bitmap.h"
#include "map_renderer.h"
#include "screen_point.h"
#include "shared_ptr.h"
#include "streambuf_operators.h"

// --------------------------------------------------------------------------
// Unnamed namespace
// --------------------------------------------------------------------------

namespace
{

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	char const k_file_name[] = "entire_map.bmp";

	// --------------------------------------------------------------------------
	// t_entire_map_bitmap_creater class
	// --------------------------------------------------------------------------

	class t_entire_map_bitmap_creater : private t_map_renderer::t_client
	{
	public:
		// Operator
		std::auto_ptr< t_abstract_bitmap16 >	operator()(
													t_abstract_adventure_map const &	adventure_map,
													int									level );

	private:
		// Data members
		t_shared_ptr< t_memory_bitmap16 >	m_bitmap_ptr;
		t_map_renderer *					m_renderer_ptr;

		// Member functions
		virtual t_back_buffer_ptr	create_back_buffer(
										t_screen_point const & view_size );
		virtual void				on_rects_dirtied(
										std::vector< t_screen_rect > const & dirtied_rects );
	};

	// --------------------------------------------------------------------------
	// t_entire_map_bitmap_creater class
	// --------------------------------------------------------------------------

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	std::auto_ptr< t_abstract_bitmap16 > t_entire_map_bitmap_creater::operator()(
		t_abstract_adventure_map const &	adventure_map,
		int									level )
	{
		t_map_renderer renderer( *this, adventure_map );
		m_renderer_ptr = &renderer;

		renderer.set_view_level( level );

		renderer.move_view(
			t_screen_point( 0, -k_max_tile_vertex_height ),
			adventure_map.get_view_size() + t_screen_point( 0, k_max_tile_vertex_height ) );
		assert( m_bitmap_ptr.get() != 0 );

		renderer.move_view( t_screen_point( 0, 0 ), t_screen_point( 0, 0 ) );
		assert( m_bitmap_ptr.unique() );

		std::auto_ptr< t_abstract_bitmap16 > result( m_bitmap_ptr.release().release() );
		return result;
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_entire_map_bitmap_creater::t_back_buffer_ptr
	t_entire_map_bitmap_creater::create_back_buffer(
		t_screen_point const &	view_size )
	{
		m_bitmap_ptr = new t_memory_bitmap16( view_size.x, view_size.y );
		return m_bitmap_ptr;
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	void t_entire_map_bitmap_creater::on_rects_dirtied(
		std::vector< t_screen_rect > const &	dirtied_rects )
	{
		std::vector< t_screen_rect >::const_iterator rect_end = dirtied_rects.end();
		std::vector< t_screen_rect >::const_iterator rect_iter = dirtied_rects.begin();
		for ( ; rect_iter != rect_end; ++rect_iter )
			m_renderer_ptr->update( *rect_iter );
	}

	// --------------------------------------------------------------------------
	// Non-member functions
	// --------------------------------------------------------------------------

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	void write_bitmap(
		std::streambuf &			stream,
		t_abstract_bitmap16 const &	bitmap )
	{
		BITMAPFILEHEADER file_header;
		memset( &file_header, 0, sizeof( file_header ) );
		memcpy( &file_header.bfType, "BM", 2 );
		file_header.bfSize =
				sizeof( BITMAPFILEHEADER )
			+	sizeof( BITMAPINFOHEADER )
			+	bitmap.get_width() * bitmap.get_height() * 3;
		file_header.bfOffBits =
				sizeof( BITMAPFILEHEADER )
			+	sizeof( BITMAPINFOHEADER );

		write( stream, &file_header, sizeof( file_header ) );

		BITMAPINFOHEADER info_header;
		memset( &info_header, 0, sizeof( info_header ) );
		info_header.biSize = sizeof( info_header );
		info_header.biWidth = bitmap.get_width();
		info_header.biHeight = bitmap.get_height();
		info_header.biPlanes = 1;
		info_header.biBitCount = 24;
		info_header.biCompression = BI_RGB;

		write( stream, &info_header, sizeof( info_header ) );

		int height = bitmap.get_height();
		int width = bitmap.get_width();

		t_uint16 const * source_line_ptr = bitmap.advance_line( bitmap.get_data_ptr(), height - 1 );
		int y;
		for ( y = 0; y < height; ++y, source_line_ptr = bitmap.advance_line( source_line_ptr, -1 ) )
		{
			t_uint16 const * source_ptr = source_line_ptr;
			int x;
			for ( x = 0; x < width; ++x, ++source_ptr )
			{
				t_pixel_24 pixel_24 = convert_to_24_bit( *source_ptr );
				write( stream, &pixel_24, sizeof( pixel_24 ) );
			}
		}
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	void write_bitmap( t_abstract_bitmap16 const & bitmap )
	{
		std::filebuf stream;
		if ( stream.open( k_file_name, std::ios::out | std::ios::binary ) != 0 )
			write_bitmap( stream, bitmap );
	}

} // Unnamed namespace

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void dump_entire_map_image(
	t_abstract_adventure_map const &	adventure_map,
	int									level )
{
	t_entire_map_bitmap_creater create_entire_map_bitmap;
	write_bitmap( *create_entire_map_bitmap( adventure_map, level ) );
}
